package cn.zhuama.common.service;

import cn.zhuama.basic.exception.BusinessException;
import cn.zhuama.basic.util.*;
import cn.zhuama.common.domain.LogininfoData;
import cn.zhuama.org.domain.Logininfo;
import cn.zhuama.org.mapper.EmployeeMapper;
import cn.zhuama.org.mapper.LogininfoMapper;
import cn.zhuama.system.domain.Menu;
import cn.zhuama.user.constant.WeChatContant;
import cn.zhuama.user.domain.Wxuser;
import cn.zhuama.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ser.std.StdKeySerializers;
import com.fasterxml.jackson.databind.type.MapLikeType;
import jdk.nashorn.api.scripting.AbstractJSObject;
import netscape.javascript.JSObject;
import org.apache.poi.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static cn.zhuama.basic.util.JwtUtils.generateTokenExpireInSeconds;

@Service
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class LoginService {
    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    LogininfoMapper logininfoMapper;

    @Autowired
    WxuserMapper wxuserMapper;

    @Autowired
    EmployeeMapper employeeMapper;

    //优化代码的话这里可以只用req 找到他的taken中带的data 这个是错误的 req中的header只带了token
    public String noToken(Map<String, Object> mapl) {
        //优化的话应该是提取一个init初始化对象
        //1.参数检验
        if (mapl.get("username") == null || mapl.get("password") == null) {
            throw new BusinessException("账号或密码为空");
        }
        if (redisTemplate.opsForValue().get("username") == null) {
            //这两步没什么意义啊 有意义 这样第二次进来可以直接用！
            redisTemplate.opsForValue().set("username", mapl.get("username"));
            redisTemplate.opsForValue().set("password", mapl.get("password"));
            redisTemplate.opsForValue().set("type", mapl.get("type"));
        }
        //这步我是用来测试和方便使用的
        String username = (String) redisTemplate.opsForValue().get("username");
        String password = (String) redisTemplate.opsForValue().get("password");
        Integer type = (Integer) redisTemplate.opsForValue().get("type");
        //先找出来这个人 找到他的salt和密码
        Logininfo logininfo = logininfoMapper.queryByUsernameAndType(mapl);

        if (logininfo != null) {
            //若是有这个人
            String newpassword = Md5Utils.encrypByMd5(logininfo.getSalt() + password);
            //加salt加密码来判断 账号密码
            if (username.equals(logininfo.getUsername()) && newpassword.equals(logininfo.getPassword())) {
                //账号密码正确
                //有账号密码初次进入 先生成一个token值 给他存进去然后放回去 存到redis中
                String token = UUID.randomUUID().toString();
                //根据这个token 直接存了找到的这个对象 给个三十分钟有效期 不然拦截器不好管
                redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
                return token;
            } else {
                //账号密码 错误 抛出异常
                throw new BusinessException("账号密码错误");
            }
        }else {
            //账号密码 错误 抛出异常
            throw new BusinessException("账号不存在 查无此人");
        }


}
public String noTokenJWT(Map<String, Object> mapl) throws Exception {
        //这个方法用来生成加密token
        if (mapl.get("username") == null || mapl.get("password") == null) {
            throw new BusinessException("账号或密码为空");
        }
        //这步我是用来测试和方便使用的
        String username = (String) mapl.get("username");
        String password = (String) mapl.get("password");
        Integer type = (Integer) mapl.get("type");
        //先找出来这个人 找到他的salt和密码
        Logininfo logininfo = logininfoMapper.queryByUsernameAndType(mapl);

        if (logininfo != null) {
            //若是有这个人
            String newpassword = Md5Utils.encrypByMd5(logininfo.getSalt() + password);
            //加salt加密码来判断 账号密码
            if (username.equals(logininfo.getUsername()) && newpassword.equals(logininfo.getPassword())) {
                //账号密码正确
                //有账号密码初次进入 先生成一个token值 给他存进去然后放回去
                //生成一个加密后的 私钥
                //先搞个data
                LogininfoData logininfoData = new LogininfoData();
                logininfoData.setLogininfo(logininfo);
                // 1 获取token
                //我前端就没用这个数据logininfoData 前端是根据map中的值拿的。。。哈哈哈 所以这个token不完整
//                //权限
//                List<String> permission = employeeMapper.loadPerssionSnByLogininfoId(logininfo.getId());
//                //目录 全部
//                List<Menu> menus = employeeMapper.loadMenuSnByLogininfoId(logininfo.getId());
//                logininfoData.setMenus(menus);
//                logininfoData.setPermission(permission);
                //这样生成的key才包含全部信息
                PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource("auth_rsa.pri").getFile());
                String token = generateTokenExpireInSeconds(logininfoData, privateKey, 3600);
                return token;
            } else {
                //账号密码 错误 抛出异常
                throw new BusinessException("账号密码错误");
            }
        }else {
            //账号密码 错误 抛出异常
            throw new BusinessException("账号不存在 查无此人");
        }


}

    public Map<String,Object> fz(Map<String, Object> mapl) {
        Map nmap = new HashMap<String,Object>();
        Logininfo logininfo = logininfoMapper.queryByUsernameAndType(mapl);
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        nmap.put("token",mapl.get("token"));
        nmap.put("logininfo",logininfo);
        return  nmap;

    }

    public AjaxResult wxlogin(String code) {
        //参数检验 逻辑判断 业务实现
        //参数检验 code是否传进来
        if(code==null){
            return AjaxResult.me().setSuccess(false);
        }
        //逻辑判断
        //先找到令牌和相关信息
       // https://api.weixin.qq.com/sns/oauth2/access_token?
        // appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
        //这钩子怎么拼接的啊 我还不会
         String baseUrl = WeChatContant.wxUrl // 获取基础URL
        .replace("APPID",WeChatContant.APPID)
        .replace("SECRET",WeChatContant.SECRET)
        .replace("CODE",code);
//        System.out.println(baseUrl);
        //从这里拿到JSON格式的含有令牌的路由 转换一哈
        //这行到底为啥报错呢 我ri
        String jsonStr= HttpUtil.httpGet(baseUrl);
        //然后将这个json字符串 转换成json格式的对象
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        //找到对应的令牌和oppenid 在本地数据库查找
        String access_token = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        //查本地这个表有没得 这个人
        Wxuser wxuser = wxuserMapper.loadByOpenid(openid);
        if(wxuser!=null && wxuser.getUser_id()!=null){
            //意味着 有这个微信对象 而且已经绑定了用户 直接免密登录 通过userid找到logininfo id登录
            Logininfo logininfo = logininfoMapper.loadLogininfoByUserId(wxuser.getUser_id());
            //登录自带token 不多说了 相当于登陆者的令牌
            String token = UUID.randomUUID().toString();
            //去掉salt和密码 存在本地
            logininfo.setSalt(null);
            logininfo.setPassword(null);
            redisTemplate.opsForValue().set(token,logininfo,30,TimeUnit.MINUTES);
            Map<String, Object> map = new HashMap<>();
            map.put("token",token);
            map.put("logininfo",logininfo);
            return AjaxResult.me().setObject(map);
        }else{
            //没有 则说明未绑定 要跳转到绑定页面 把令牌和id带给他们
            Map<String,Object> map = new HashMap<>();
            map.put("access_token",access_token);
            map.put("openid",openid);
            return AjaxResult.me().setSuccess(false).setObject(map);
        }


    }

    public Map<String, Object> fzMap(Map<String, Object> mapl) {
        //时间
        mapl.put("oldTime",System.currentTimeMillis());
        Logininfo logininfo = (Logininfo) mapl.get("logininfo");
        //权限
        List<String> permission = employeeMapper.loadPerssionSnByLogininfoId(logininfo.getId());
        mapl.put("permissions",permission);
        //目录 全部
        List<Menu> menus = employeeMapper.loadMenuSnByLogininfoId(logininfo.getId());
        mapl.put("menus",menus);
        //我感觉这里其实也可以把这东西东西封装到 LogininfoDATA里面 然后穿个对象 不过用map也可以
        return mapl;

    }
}
